﻿#include "FITKAcousticsVTKSharedDataManager.h"

// Qt
#include <QFile>
#include <QDir>

// VTK
#include <vtkPoints.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkUnstructuredGrid.h>
#include <vtkIdList.h>
#include <vtkSmartPointer.h>
#include <vtkIntArray.h>
#include <vtkCellData.h>
#include <vtkUnsignedCharArray.h>
#include <vtkImageData.h>
#include <vtkPNGReader.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKRunTimeSetting.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Global data
#include "FITK_Kernel/FITKCore/FITKDataRepo.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfacePhysics/FITKAbstractSection.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysBeam.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysAbsShell.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysCavity.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEAFace.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAAbstractJunction.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAJunctionPoint.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAJunctionLine.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAJunctionArea.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEASubSysGeoProp.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsTriangles.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEFace.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKFESubSysAcoustic.h"
#include "FITK_Component/FITKAcousticsModel/FITKFESubSysStructure.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsPhysicsProp.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsAbsNCT.h"
#include "FITK_Component/FITKAcousticsPhysics/FITKAcousticsMaterialsFluid.h"

// Graph
#include "FITKAcousticsVTKCommons.h"

namespace Exchange
{
    // Inistailize the static instance.
    FITKAcousticsVTKSharedDataManager* FITKAcousticsVTKSharedDataManager::s_instance{ nullptr };

    FITKAcousticsVTKSharedDataManager* FITKAcousticsVTKSharedDataManager::GetInstance()
    {
        if (!s_instance)
        {
            s_instance = new FITKAcousticsVTKSharedDataManager;
        }

        return s_instance;
    }

    void FITKAcousticsVTKSharedDataManager::Destory()
    {
        if (s_instance)
        {
            delete s_instance;
        }

        s_instance = nullptr;
    }

    FITKAcousticsVTKSharedDataManager::FITKAcousticsVTKSharedDataManager()
    {
        // Create the SEA node data.
        m_SEANodesPoints = vtkPoints::New();

        // Get the SEA-model data.
        m_discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();

        if (m_discModel)
        {
            m_SEAModel = m_discModel->getSEAModel();
            m_FEModel = m_discModel->getFEModel();
        }

        // Get the SEA nodes and SEA sub-system manager..
        if (m_SEAModel)
        {
            Acoustics::FITKAcousticsDiscModel* discModel = FITKGLODATA->getMeshData<Acoustics::FITKAcousticsDiscModel>();
            if (!discModel)return;

            // Get the SEA nodes data list.
            m_SEANodes = discModel->getNodes();
            m_SEASubSysMgr = m_SEAModel->getSEASubSysManager();
            m_SEAJuncMgr = discModel->getJunctionManager();
        }
    }

    FITKAcousticsVTKSharedDataManager::~FITKAcousticsVTKSharedDataManager()
    {
        // Delete data.
        if (m_SEANodesPoints)
        {
            m_SEANodesPoints->Delete();
            m_SEANodesPoints = nullptr;
        }

        // Delete the multi block datasets.
        deleteVtkObjs(m_SEASubSystemsDataSetHash);
        deleteVtkObjs(m_SEASubSystemsBoundDataSetHash);
        deleteVtkObjs(m_SEAJunctionsDataSetHash);

        // Delete the picture data.
        for (vtkImageData* img : m_picDataDict.values())
        {
            if (img)
            {
                img->Delete();
            }
        }
        
        m_picDataDict.clear();
        m_SEASubSysDataSetHash.clear();
        m_SEASubSysBoundDataSetHash.clear();
        m_SEAJuncDataSetHash.clear();
        m_SEASubSysDataObjDataSetHash.clear();
        m_SEASubSysDataObjBdsDataSetHash.clear();
        m_SEAJuncDataObjDataSetHash.clear();
    }

    vtkPoints* FITKAcousticsVTKSharedDataManager::getSEANodesPoints(bool reCreate)
    {
        // If the SEA points data exists and the nodes count is not zero, and also the 'reCreate' is false,
        // return the current SEA nodes points, else re-create the points data.
        if (!m_SEANodesPoints || m_SEANodesPoints->GetNumberOfPoints() == 0 || reCreate)
        {
            if (!m_SEANodesPoints)
            {
                m_SEANodesPoints = vtkPoints::New();
            }
            else
            {
                m_SEANodesPoints->Reset();
            }

            m_SEANodesPoints->SetNumberOfPoints(0);

            // Get the SEA nodes.
            if (!m_SEANodes)
            {
                return m_SEANodesPoints;
            }

            double pos3[3]{ 0., 0., 0. };
            int nSeaNodes = m_SEANodes->getNodeCount();
            for (int i = 0; i < nSeaNodes; i++)
            {
                // Add a ( 0., 0., 0.) point while the node is invalid.
                Core::FITKNode* node = m_SEANodes->getNodeAt(i);
                if (node)
                {
                    node->getCoor(pos3);
                }

                m_SEANodesPoints->InsertNextPoint(pos3);
            }
        }

        return m_SEANodesPoints;
    }

    bool FITKAcousticsVTKSharedDataManager::getSEANodesBounds(double* bds6)
    {
        vtkPoints* seaPoints = getSEANodesPoints();
        if (!seaPoints)
        {
            return false;
        }

        // Get the bounds.
        double* bds = seaPoints->GetBounds();
        for (int i = 0; i < 6; i++)
        {
            bds6[i] = bds[i];
        }

        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::getSEANodesCenter(double* pos3)
    {
        // Get the bounds.
        double bds6[6]{ 0., 0., 0., 0., 0., 0. };
        if (!getSEANodesBounds(bds6))
        {
            return false;
        }

        for (int i = 0; i < 3; i++)
        {
            pos3[i] = (bds6[i * 2] + bds6[i * 2 + 1]) * 0.5;
        }

        return true;
    }

    vtkMultiBlockDataSet* FITKAcousticsVTKSharedDataManager::getSEASubSystemsMultiDataSet(int seaSubSysEnum)
    {
        // Type value check.
        vtkMultiBlockDataSet* mDataSet{ nullptr };
        switch (seaSubSysEnum)
        {
        case Acoustics::FITKAbstractSEASubSys::SEABeam:
        case Acoustics::FITKAbstractSEASubSys::SEAFlatPlate:
        case Acoustics::FITKAbstractSEASubSys::SEASinglyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEADoublyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEACylinderShell:
        case Acoustics::FITKAbstractSEASubSys::SEACavity:
            break;
        default:
            return nullptr;
        }

        // Get or create the dataset by the sub-system type.
        if (m_SEASubSystemsDataSetHash.contains(seaSubSysEnum))
        {
            mDataSet = m_SEASubSystemsDataSetHash[seaSubSysEnum];
        }
        else
        {
            mDataSet = vtkMultiBlockDataSet::New();
            m_SEASubSystemsDataSetHash.insert(seaSubSysEnum, mDataSet);
        }

        return mDataSet;
    }

    vtkMultiBlockDataSet* FITKAcousticsVTKSharedDataManager::getSEASubSystemsBoundaryMultiDataSet(int seaSubSysEnum)
    {
        // Type value check.
        vtkMultiBlockDataSet* mDataSet{ nullptr };
        switch (seaSubSysEnum)
        {
        case Acoustics::FITKAbstractSEASubSys::SEABeam:
        case Acoustics::FITKAbstractSEASubSys::SEAFlatPlate:
        case Acoustics::FITKAbstractSEASubSys::SEASinglyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEADoublyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEACylinderShell:
        case Acoustics::FITKAbstractSEASubSys::SEACavity:
            break;
        default:
            return nullptr;
        }

        // Get or create the dataset by the sub-system type.
        if (m_SEASubSystemsBoundDataSetHash.contains(seaSubSysEnum))
        {
            mDataSet = m_SEASubSystemsBoundDataSetHash[seaSubSysEnum];
        }
        else
        {
            mDataSet = vtkMultiBlockDataSet::New();
            m_SEASubSystemsBoundDataSetHash.insert(seaSubSysEnum, mDataSet);
        }

        return mDataSet;
    }

    vtkMultiBlockDataSet * FITKAcousticsVTKSharedDataManager::getFEFaceMultiDataSet()
    {
        if (m_FEFaceObjDataSet == nullptr)
            m_FEFaceObjDataSet = vtkMultiBlockDataSet::New();
        return m_FEFaceObjDataSet;
    }

    vtkMultiBlockDataSet * FITKAcousticsVTKSharedDataManager::getFESubSysMultiDataSet(int seaSubSysEnum)
    {
        vtkMultiBlockDataSet* mDataSet = nullptr;

        //判断是否存在
        if (m_FESubSysDataObjSetHash.contains(seaSubSysEnum)){
            mDataSet = m_FESubSysDataObjSetHash[seaSubSysEnum];
        }
        else{
            mDataSet = vtkMultiBlockDataSet::New();
            m_FESubSysDataObjSetHash.insert(seaSubSysEnum, mDataSet);
        }

        return mDataSet;
    }

    vtkDataSet* FITKAcousticsVTKSharedDataManager::getSEASubSystemDataSet(int dataId, int & blockIndex)
    {
        blockIndex = -1;

        // ID check.
        if (!m_SEASubSysMgr)
        {
            return nullptr;
        }

        // Get the sub-system data.
        Acoustics::FITKAbstractSEASubSys* subSys = m_SEASubSysMgr->getDataByID(dataId);
        if (!subSys)
        {
            return nullptr;
        }

        // Find the dataset.
        vtkDataSet* dataSet = m_SEASubSysDataSetHash.value(subSys, nullptr);
        if (!dataSet)
        {
            return nullptr;
        }

        // Get the multi block dataset and find the index of the sub dataset.
        vtkMultiBlockDataSet* mDataSet = m_SEASubSystemsDataSetHash.value(subSys->getSEASubSysType(), nullptr);
        if (!mDataSet)
        {
            return dataSet;
        }

        int nBlocks = mDataSet->GetNumberOfBlocks();
        for (int i = 0; i < nBlocks; i++)
        {
            if (dataSet == mDataSet->GetBlock(i))
            {
                blockIndex = i;
                break;
            }
        }

        return dataSet;
    }

    vtkDataSet * FITKAcousticsVTKSharedDataManager::getSEASubSystemBoundaryDataSet(int dataId, int & blockIndex)
    {
        blockIndex = -1;

        // ID check.
        if (!m_SEASubSysMgr)
        {
            return nullptr;
        }

        // Get the sub-system data.
        Acoustics::FITKAbstractSEASubSys* subSys = m_SEASubSysMgr->getDataByID(dataId);
        if (!subSys)
        {
            return nullptr;
        }

        // Find the dataset.
        vtkDataSet* dataSet = m_SEASubSysBoundDataSetHash.value(subSys, nullptr);
        if (!dataSet)
        {
            return nullptr;
        }

        // Get the multi block dataset and find the index of the sub dataset.
        vtkMultiBlockDataSet* mDataSet = m_SEASubSystemsBoundDataSetHash.value(subSys->getSEASubSysType(), nullptr);
        if (!mDataSet)
        {
            return dataSet;
        }

        int nBlocks = mDataSet->GetNumberOfBlocks();
        for (int i = 0; i < nBlocks; i++)
        {
            if (dataSet == mDataSet->GetBlock(i))
            {
                blockIndex = i;
                break;
            }
        }

        return dataSet;
    }

    vtkDataSet* FITKAcousticsVTKSharedDataManager::getFEFacesDataSet(int dataId, int & blockIndex)
    {
        blockIndex = -1;

        //判断FE面管理器是否存在
        if (m_FEModel == nullptr || m_FEModel->getFEFaceManager() == nullptr){
            return nullptr;
        }

        //获取数据对象对应的FE对象
        Acoustics::FITKAcousticsFEFace* feFace = m_FEModel->getFEFaceManager()->getDataByID(dataId);
        if (!feFace){
            return nullptr;
        }

        //通过数据id查找数据对象
        vtkDataSet* dataSet = m_FEFaceDataSetHash.value(feFace, nullptr);
        if (dataSet == nullptr){
            return nullptr;
        }

        if (m_FEFaceObjDataSet == nullptr) {
            return dataSet;
        }

        int nBlocks = m_FEFaceObjDataSet->GetNumberOfBlocks();
        for (int i = 0; i < nBlocks; i++)
        {
            if (dataSet == m_FEFaceObjDataSet->GetBlock(i)){
                blockIndex = i;
                break;
            }
        }

        return dataSet;
    }

    vtkDataSet * FITKAcousticsVTKSharedDataManager::getFESubSystemDataSet(int dataId, int & blockIndex)
    {
        blockIndex = -1;
        if (m_FEModel == nullptr || m_FEModel->getFESubSysManager() == nullptr) {
            return nullptr;
        }

        Acoustics::FITKAbstractFESubSys* feSubSys = m_FEModel->getFESubSysManager()->getDataByID(dataId);
        if (feSubSys == nullptr) {
            return nullptr;
        }

        vtkDataSet* dataSet = m_FESubSysDataSetHash.value(feSubSys);
        if (dataSet == nullptr) {
            return nullptr;
        }

        vtkMultiBlockDataSet* multiBlockData = getFESubSysMultiDataSet(feSubSys->getFESubSysType());
        if (multiBlockData == nullptr) {
            return dataSet;
        }

        int nBlocks = multiBlockData->GetNumberOfBlocks();
        for (int i = 0; i < nBlocks; i++)
        {
            if (dataSet == multiBlockData->GetBlock(i)) {
                blockIndex = i;
                break;
            }
        }

        return dataSet;
    }

    bool FITKAcousticsVTKSharedDataManager::updateSEASubSystemDataSet(int dataId)
    {
        // ID check.
        if (!m_SEASubSysMgr)
        {
            return false;
        }

        // Get the sub-system type.
        Acoustics::FITKAbstractSEASubSys* subSys = m_SEASubSysMgr->getDataByID(dataId);
        if (!subSys)
        {
            return false;
        }

        // Generate the data and add to the multi dataset.
        Acoustics::FITKAbstractSEASubSys::SEASubSysType ssType = subSys->getSEASubSysType();
        vtkMultiBlockDataSet* mDataSet = getSEASubSystemsMultiDataSet(ssType);
        vtkMultiBlockDataSet* mDataSetBds = getSEASubSystemsBoundaryMultiDataSet(ssType);
        if (!mDataSet || !mDataSetBds)
        {
            return false;
        }
        
        QHash<int, int> nodeIdPointIndexHash;
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

        vtkSmartPointer<vtkUnstructuredGrid> ugrid = vtkSmartPointer<vtkUnstructuredGrid>::New();       
        ugrid->SetPoints(points);

        vtkSmartPointer<vtkUnstructuredGrid> ugridBds = vtkSmartPointer<vtkUnstructuredGrid>::New();
        ugridBds->SetPoints(points);

        // The data id array.
        vtkSmartPointer<vtkIntArray> idArray = vtkSmartPointer<vtkIntArray>::New();
        idArray->SetName(DATA_ID_ARRAY_NAME);
        
        // The sub id array for the SEA faces ( or beam segent index ).
        vtkSmartPointer<vtkIntArray> subIdArray = vtkSmartPointer<vtkIntArray>::New();
        subIdArray->SetName(DATA_SUB_ID_ARRAY_NAME);

        // The element id array for the elements.
        vtkSmartPointer<vtkIntArray> elemIdArray = vtkSmartPointer<vtkIntArray>::New();
        elemIdArray->SetName(DATA_ELEM_ID_ARRAY_NAME);
        
        vtkCellData* cellData = ugrid->GetCellData();
        if (cellData)
        {    
            cellData->AddArray(idArray);
            cellData->AddArray(subIdArray);
        }

        switch (ssType)
        {
        case Acoustics::FITKAbstractSEASubSys::SEABeam:
        {
            Acoustics::FITKSEASubSysBeam* beam = dynamic_cast<Acoustics::FITKSEASubSysBeam*>(subSys);
            if (!beam)
            {
                return false;
            }

            // Get the beam nodes.
            QList<int> ids = beam->getNodeIDs();

            // Remove the last direction node.
            ids.removeLast();

            // Old version.
            //@{
            //vtkSmartPointer<vtkIdList> polyLineCell = vtkSmartPointer<vtkIdList>::New();
            //double pos3[3]{ 0., 0., 0. };
            //for (const int & nId : ids)
            //{
            //    Core::FITKNode* node = m_SEANodes->getNodeByID(nId);
            //    if (!node)
            //    {
            //        continue;
            //    }

            //    node->getCoor(pos3);

            //    // Insert the node and insert a point to the poly line.
            //    int iPt = points->InsertNextPoint(pos3);
            //    polyLineCell->InsertNextId(iPt);
            //}

            //// Add the poly line to the grid.
            //ugrid->InsertNextCell(VTKCellType::VTK_POLY_LINE, polyLineCell);
            //@}

            // New version.
            //@{
            // Add points.
            double pos3[3]{ 0., 0., 0. };
            for (const int & nId : ids)
            {
                bool flag = FITKAcousticsVTKCommons::GetSEANodePositionById(m_SEANodes, nId, pos3);
                Q_UNUSED(flag);

                // Insert the node and insert a point to the poly line.
                points->InsertNextPoint(pos3);
            }

            // Add cells and sub-id data.
            for (int i = 0; i < ids.count() - 1; i++)
            {
                vtkSmartPointer<vtkIdList> lineCell = vtkSmartPointer<vtkIdList>::New();
                lineCell->InsertNextId(i);
                lineCell->InsertNextId(i + 1);
                ugrid->InsertNextCell(VTKCellType::VTK_LINE, lineCell);

                subIdArray->InsertNextValue(i);
            }
            //@}

            break;
        }
        case Acoustics::FITKAbstractSEASubSys::SEAFlatPlate:
        case Acoustics::FITKAbstractSEASubSys::SEASinglyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEADoublyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEACylinderShell:
        {
            Acoustics::FITKAbstractSEASubSysShell* shell = dynamic_cast<Acoustics::FITKAbstractSEASubSysShell*>(subSys);
            if (!shell)
            {
                return false;
            }

            if (cellData)
            {
                cellData->AddArray(elemIdArray);
            }

            // Get the default shell color.
            QColor defaultColor;
            Acoustics::FITKAcousticsAbsPhysicsProp* phyProp = shell->getPropSectionObj();
            if (phyProp)
            {
                float phyColor3[3]{ 0., 0., 0. };
                phyProp->getColor(phyColor3);
                defaultColor = QColor::fromRgbF(phyColor3[0], phyColor3[1], phyColor3[2]);
            }
            else
            {
                defaultColor = FITKAcousticsVTKCommons::s_SEASubSysShellColor;
            }

            // Try to get the NCT color.
            Acoustics::FITKAcousticsAbsNCT* oNCT = shell->getOutsideNCT();
            Acoustics::FITKAcousticsAbsNCT* iNCT = shell->getInsideNCT();

            QColor colorIn, colorOut;

            if (oNCT)
            {
                float color3[3]{ 0., 0., 0. };
                oNCT->getColor(color3);
                colorOut = QColor::fromRgbF(color3[0], color3[1], color3[2]);
            }
            else
            {
                colorOut = defaultColor;
            }

            if (iNCT)
            {
                float color3[3]{ 0., 0., 0. };
                iNCT->getColor(color3);
                colorIn = QColor::fromRgbF(color3[0], color3[1], color3[2]);
            }
            else
            {
                colorIn = defaultColor;
            }

            // Generate points.
            generateSEASubSysNodes(shell, points, nodeIdPointIndexHash);

            // Get all triangles.
            Acoustics::FITKAcousticsTriangles* tris = shell->getTriangleMesh();
            if (!tris)
            {
                return false;
            }

            int faceId = shell->getFaceID();
            int nTris = tris->getElementCount();

            // Malloc array.
            subIdArray->SetNumberOfValues(nTris * 2);
            elemIdArray->SetNumberOfValues(nTris * 2);

            // Add face id.
            subIdArray->FillComponent(0, faceId);

            for (int i = 0; i < nTris; i++)
            {
                Interface::FITKAbstractElement* tri = tris->getElementAt(i);
                if (!tri)
                {
                    continue;
                }

                // Check the triangle.
                int nNodes = tri->getNodeCount();
                if (nNodes != 3)
                {
                    continue;
                }

                // Get the node ids.
                int nodeId_1 = tri->getNodeID(0);
                int nodeId_2 = tri->getNodeID(1);
                int nodeId_3 = tri->getNodeID(2);

                // Get the node indice.
                int ptIndex_1 = nodeIdPointIndexHash.value(nodeId_1, -1);
                int ptIndex_2 = nodeIdPointIndexHash.value(nodeId_2, -1);
                int ptIndex_3 = nodeIdPointIndexHash.value(nodeId_3, -1);

                if (ptIndex_1 == -1 || ptIndex_2 == -1 || ptIndex_3 == -1)
                {
                    qDebug() << QString("Invalid node id in SEA sub-systems!");
                    qDebug() << QString("Triangle node ids: %1, %2, %3.").arg(nodeId_1).arg(nodeId_2).arg(nodeId_3);
                    qDebug() << QString("Triangle node indice in VTK: %1, %2, %3.").arg(ptIndex_1).arg(ptIndex_2).arg(ptIndex_3);
                    continue;
                }

                // Add a triangle cell.
                vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                cell->InsertNextId(ptIndex_1);
                cell->InsertNextId(ptIndex_2);
                cell->InsertNextId(ptIndex_3);
                ugrid->InsertNextCell(VTKCellType::VTK_TRIANGLE, cell);

                // Add element id( index ).
                // The element id is -1.
                //int eleId = tri->getEleID();
                //Q_UNUSED(eleId);

                elemIdArray->SetValue(i, i); // Front face.
                elemIdArray->SetValue(i + nTris, i); // Back face.
            }

            // Add reversed cells as back faces.
            int nCells = ugrid->GetNumberOfCells();
            for (int i = 0; i < nCells; i++)
            {
                vtkCell* cell = ugrid->GetCell(i);
                int cType = cell->GetCellType();

                vtkSmartPointer<vtkIdList> rCell = vtkSmartPointer<vtkIdList>::New();
                for (int j = cell->GetNumberOfPoints() - 1; j >= 0; j--)
                {
                    rCell->InsertNextId(cell->GetPointId(j));
                }

                ugrid->InsertNextCell(cType, rCell);
            }

            // Update the data color array.
            setDataSetColor(ugrid, colorOut, colorIn, DATA_COLOR_ARRAY_NAME);

            // Get the geometry properties from the sub-system.
            Acoustics::FITKSEASubSysGeoProp* shellProp = shell->getGeoProp();
            if (shellProp)
            {
                // Generate the boundary edges cells.
                QList<QPair<int, int>> edges = shellProp->getBoundary();

                for (const QPair<int, int> & edge : edges)
                {
                    int ptIndex_1 = nodeIdPointIndexHash.value(edge.first, -1);
                    int ptIndex_2 = nodeIdPointIndexHash.value(edge.second, -1);

                    if (ptIndex_1 == -1 || ptIndex_2 == -1)
                    {
                        qDebug() << QString("Invalid node id in SEA sub-systems boundary!");
                        qDebug() << QString("Boundary line node ids: %1, %2.").arg(edge.first).arg(edge.second);
                        qDebug() << QString("Boundary line node indice in VTK: %1, %2.").arg(ptIndex_1).arg(ptIndex_2);
                        continue;
                    }

                    // Create the line cell.
                    vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                    cell->InsertNextId(ptIndex_1);
                    cell->InsertNextId(ptIndex_2);
                    ugridBds->InsertNextCell(VTKCellType::VTK_LINE, cell);
                }
            }

            break;
        }
        case Acoustics::FITKAbstractSEASubSys::SEACavity:
        {
            Acoustics::FITKSEASubSysCavity* cavity = dynamic_cast<Acoustics::FITKSEASubSysCavity*>(subSys);
            if (!cavity)
            {
                return false;
            }

            if (cellData)
            {
                cellData->AddArray(elemIdArray);
            }

            // Generate points.
            generateSEASubSysNodes(cavity, points, nodeIdPointIndexHash);

            // Get the face count.
            int nFaces = cavity->getFaceCount();

            double centerTemp3[3]{ 0., 0., 0. };
            for (int i = 0; i < nFaces; i++)
            {
                Acoustics::FITKAbstractSEAFace* subFace = cavity->getFace(i);
                if (!subFace)
                {
                    continue;
                }

                int faceId = subFace->getDataObjectID();

                // Get all triangles.
                Acoustics::FITKAcousticsTriangles* tris = subFace->getTriangleMesh();
                if (!tris)
                {
                    return false;
                }

                double boundsFace6[6]{ 0., 0., 0., 0., 0., 0. };

                int nTris = tris->getElementCount();
                for (int j = 0; j < nTris; j++)
                {
                    Interface::FITKAbstractElement* tri = tris->getElementAt(j);
                    if (!tri)
                    {
                        continue;
                    }

                    // Check the triangle.
                    int nNodes = tri->getNodeCount();
                    if (nNodes != 3)
                    {
                        continue;
                    }

                    // Get the node ids.
                    int nodeId_1 = tri->getNodeID(0);
                    int nodeId_2 = tri->getNodeID(1);
                    int nodeId_3 = tri->getNodeID(2);

                    // Get the node indice.
                    int ptIndex_1 = nodeIdPointIndexHash.value(nodeId_1, -1);
                    int ptIndex_2 = nodeIdPointIndexHash.value(nodeId_2, -1);
                    int ptIndex_3 = nodeIdPointIndexHash.value(nodeId_3, -1);

                    if (ptIndex_1 == -1 || ptIndex_2 == -1 || ptIndex_3 == -1)
                    {
                        qDebug() << QString("Invalid node id in SEA sub-systems!");
                        qDebug() << QString("Triangle node ids: %1, %2, %3.").arg(nodeId_1).arg(nodeId_2).arg(nodeId_3);
                        qDebug() << QString("Triangle node indice in VTK: %1, %2, %3.").arg(ptIndex_1).arg(ptIndex_2).arg(ptIndex_3);
                        continue;
                    }

                    // Add a triangle cell.
                    vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                    cell->InsertNextId(ptIndex_1);
                    cell->InsertNextId(ptIndex_2);
                    cell->InsertNextId(ptIndex_3);
                    ugrid->InsertNextCell(VTKCellType::VTK_TRIANGLE, cell);

                    // Add face id.
                    subIdArray->InsertNextValue(faceId);

                    // Add element id( index ).
                    elemIdArray->InsertNextValue(j);
                }
            }

            // Update the data color array.
            setDataSetColor(ugrid, FITKAcousticsVTKCommons::s_SEASubSysCavityColor, DATA_COLOR_ARRAY_NAME);

            // Get the geometry properties from the sub-system.
            Acoustics::FITKSEASubSysGeoProp* cavityProp = cavity->getGeoProp();
            if (cavityProp)
            {
                // Generate the boundary edges cells.
                QList<QPair<int, int>> edges = cavityProp->getBoundary();

                for (const QPair<int, int> & edge : edges)
                {
                    int ptIndex_1 = nodeIdPointIndexHash.value(edge.first, -1);
                    int ptIndex_2 = nodeIdPointIndexHash.value(edge.second, -1);

                    if (ptIndex_1 == -1 || ptIndex_2 == -1)
                    {
                        qDebug() << QString("Invalid node id in SEA sub-systems boundary!");
                        qDebug() << QString("Boundary line node ids: %1, %2.").arg(edge.first).arg(edge.second);
                        qDebug() << QString("Boundary line node indice in VTK: %1, %2.").arg(ptIndex_1).arg(ptIndex_2);
                        continue;
                    }

                    // Create the line cell.
                    vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                    cell->InsertNextId(ptIndex_1);
                    cell->InsertNextId(ptIndex_2);
                    ugridBds->InsertNextCell(VTKCellType::VTK_LINE, cell);
                }
            }

            break;
        }
        default:
            return false;
        }

        // Fill the data id array.
        idArray->SetNumberOfValues(ugrid->GetNumberOfCells());
        idArray->FillComponent(0, dataId);

        // Update the post null color array.
        QColor nullColor = FITKAcousticsVTKCommons::s_postNullColor;
        setDataSetColor(ugrid, nullColor, nullColor, DATA_POST_NULL_ARRAY_NAME);

        vtkDataSet* dataSet = m_SEASubSysDataSetHash.value(subSys, nullptr);
        vtkDataSet* dataSetBds = m_SEASubSysBoundDataSetHash.value(subSys, nullptr);
       
        m_SEASubSysDataObjDataSetHash.insert(dataId, mDataSet);
        m_SEASubSysDataObjBdsDataSetHash.insert(dataId, mDataSetBds);

        if (dataSet) // && dataSetBds
        {
            // Deep copy the dataset.
            dataSet->DeepCopy(ugrid);

            // Deep copy the boundary dataset.
            dataSetBds->DeepCopy(ugridBds);
        }
        else
        {
            // Insert the grid to the multi dataset.
            // int dataIndex = m_SEASubSysMgr->getDataIndex(subSys);
            int dataIndex = mDataSet->GetNumberOfBlocks();
            mDataSet->SetBlock(dataIndex, ugrid);
            mDataSetBds->SetBlock(dataIndex, ugridBds);

            // Save the dataset.
            m_SEASubSysDataSetHash.insert(subSys, ugrid);
            m_SEASubSysBoundDataSetHash.insert(subSys, ugridBds);
            
            // Connect delete signal.
            connect(subSys, &Acoustics::FITKAbstractSEASubSys::dataObjectDestoried, this, [&](Core::FITKAbstractDataObject* objDelete)
            {
                if (!objDelete)
                {
                    return;
                }

                int dataDelId = objDelete->getDataObjectID();

                vtkDataSet* dataSet = m_SEASubSysDataSetHash.take(objDelete);
                vtkDataSet* dataSetBds = m_SEASubSysBoundDataSetHash.take(objDelete);
                vtkMultiBlockDataSet* mDS = m_SEASubSysDataObjDataSetHash.take(dataDelId);
                vtkMultiBlockDataSet* mDSBds = m_SEASubSysDataObjBdsDataSetHash.take(dataDelId);
                
                // Remove the dataset of sub system.
                if (dataSet && mDS)
                {
                    // Remove the data from multi blcok dataset.
                    int nBlocks = mDS->GetNumberOfBlocks();
                    for (int i = 0; i < nBlocks; i++)
                    {
                        if (dataSet == mDS->GetBlock(i))
                        {
                            mDS->RemoveBlock(i);
                            break;
                        }
                    }
                }

                // Remove the boundary dataset of sub system.
                if (dataSetBds && mDSBds)
                {
                    // Remove the data from multi blcok dataset.
                    int nBlocks = mDSBds->GetNumberOfBlocks();
                    for (int i = 0; i < nBlocks; i++)
                    {
                        if (dataSetBds == mDSBds->GetBlock(i))
                        {
                            mDSBds->RemoveBlock(i);
                            break;
                        }
                    }
                }
            });
        }

        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateFESubSystemDataSet(int dataId)
    {
        if (m_FEModel == nullptr || m_FEModel->getFESubSysManager() == nullptr) {
            return false;
        }

        Acoustics::FITKAcousticsFESubSysElementList* eleList = m_FEModel->getFESubSysElementList();
        if (eleList == nullptr) {
            return false;
        }

        Acoustics::FITKAbstractFESubSys* feSubSys = m_FEModel->getFESubSysManager()->getDataByID(dataId);
        if (feSubSys == nullptr) {
            return false;
        }

        vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();

        QList<int> eleIDs = feSubSys->getElementsID();

        //添加信息数据
        vtkSmartPointer<vtkIntArray> idArray = vtkSmartPointer<vtkIntArray>::New();
        idArray->SetName(DATA_ID_ARRAY_NAME);
        //添加单元信息
        vtkSmartPointer<vtkIntArray> elemIdArray = vtkSmartPointer<vtkIntArray>::New();
        elemIdArray->SetName(DATA_ELEM_ID_ARRAY_NAME);
        //添加数据组
        vtkCellData* cellData = grid->GetCellData();
        if (cellData) {
            //存储信息数据
            cellData->AddArray(idArray);
            //存储单元数据
            cellData->AddArray(elemIdArray);
            //双面存储，两倍
            elemIdArray->SetNumberOfValues(eleIDs.size() * 2);
        }
        grid->SetPoints(points);
        switch (feSubSys->getFESubSysType())
        {
        case Acoustics::FITKAbstractFESubSys::FEStructure: {
            for (int index = 0; index < eleIDs.size(); index++) {
                Interface::FITKAbstractElement* ele = eleList->getElementByID(eleIDs[index]);
                if (ele == nullptr)continue;

                //创建单元
                vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                for (int pointID : ele->getAllNodes()) {
                    double pos3[3]{ 0., 0., 0. };
                    Core::FITKNode* node = m_SEANodes->getNodeByID(pointID);
                    if (node) {
                        node->getCoor(pos3);
                    }
                    int iPt = points->InsertNextPoint(pos3);
                    cell->InsertNextId(iPt);
                }

                //判断是板还是梁
                int eleVTKID = -1;
                switch (ele->getEleType()) {
                case Interface::FITKModelEnum::Line2:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_LINE, cell); break;
                case Interface::FITKModelEnum::Line3:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_POLY_LINE, cell); break;
                case Interface::FITKModelEnum::Tri3:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_TRIANGLE, cell); break;
                case Interface::FITKModelEnum::Tri6:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_TRIANGLE, cell); break;
                case Interface::FITKModelEnum::Quad4:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUAD, cell); break;
                case Interface::FITKModelEnum::Quad8:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_QUAD, cell); break;
                }

                elemIdArray->SetValue(eleVTKID, eleIDs[index]);
                elemIdArray->SetValue(eleVTKID + eleIDs.size(), eleIDs[index]);
            }
            break;
        }
        case Acoustics::FITKAbstractFESubSys::FEAcoustic: 
        {
            for (int index = 0; index < eleIDs.size(); index++) {
                Interface::FITKAbstractElement* ele = eleList->getElementByID(eleIDs[index]);
                if (ele == nullptr)continue;

                //创建单元
                vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();

                for (int pointID : ele->getAllNodes()) {
                    double pos3[3]{ 0., 0., 0. };
                    Core::FITKNode* node = m_SEANodes->getNodeByID(pointID);
                    if (node == nullptr)
                        continue; 
                    node->getCoor(pos3);

                    int iPt = points->InsertNextPoint(pos3);
                    cell->InsertNextId(iPt);
                }
                //单元类型判断
                switch (ele->getEleType()){
                case Interface::FITKModelEnum::Tet4:grid->InsertNextCell(VTKCellType::VTK_TETRA, cell); break;
                case Interface::FITKModelEnum::Tet10:grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_TETRA, cell); break;
                case Interface::FITKModelEnum::Wedge6:grid->InsertNextCell(VTKCellType::VTK_WEDGE, cell); break;
                case Interface::FITKModelEnum::Hex8:grid->InsertNextCell(VTKCellType::VTK_HEXAHEDRON, cell); break;
                case Interface::FITKModelEnum::Hex20:grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_HEXAHEDRON, cell); break;
                }

                elemIdArray->SetValue(index, eleIDs[index]);
                elemIdArray->SetValue(index + eleIDs.size(), eleIDs[index]);
            }
            break;
        }
        }

        //获取对应的数据块
        vtkMultiBlockDataSet* multiBlockData = getFESubSysMultiDataSet(feSubSys->getFESubSysType());

        //数组添加数据id
        idArray->SetNumberOfValues(grid->GetNumberOfCells());
        idArray->FillComponent(0, dataId);

        //记录数据
        vtkDataSet* dataSet = m_FESubSysDataSetHash.value(feSubSys, nullptr);
        if (dataSet) {
            vtkDataSet* dataSet = m_FESubSysDataSetHash[feSubSys];
            dataSet->DeepCopy(grid);
        }
        else
        {
            int dataIndex = multiBlockData->GetNumberOfBlocks();
            multiBlockData->SetBlock(dataIndex, grid);

            m_FESubSysDataSetHash.insert(feSubSys, grid);

            // Connect delete signal.
            connect(feSubSys, &Acoustics::FITKAbstractFESubSys::dataObjectDestoried, this, [&](Core::FITKAbstractDataObject* objDelete)
            {
                if (!objDelete) {
                    return;
                }

                int dataDelId = objDelete->getDataObjectID();

                vtkDataSet* dataSet = m_FESubSysDataSetHash.take(objDelete);
                vtkMultiBlockDataSet* mDS = m_FESubSysDataObjSetHash.take(dataDelId);
                if (dataSet && mDS)
                {
                    //清除数据块中的当前数据
                    int nBlocks = mDS->GetNumberOfBlocks();
                    for (int i = 0; i < nBlocks; i++)
                    {
                        if (dataSet == mDS->GetBlock(i))
                        {
                            mDS->RemoveBlock(i);
                            break;
                        }
                    }
                }
            });
        }
        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateSEASubSystemDataSetColor(int dataId)
    {
        // ID check.
        if (!m_SEASubSysMgr)
        {
            return false;
        }

        // Get the sub-system type.
        Acoustics::FITKAbstractSEASubSys* subSys = m_SEASubSysMgr->getDataByID(dataId);
        if (!subSys)
        {
            return false;
        }

        int dataIndex = -1;
        vtkDataSet* dataSet = FITKAcousticsVTKSharedDataManager::GetInstance()->getSEASubSystemDataSet(dataId, dataIndex);
        Q_UNUSED(dataIndex);

        if (!dataSet)
        {
            return false;
        }

        // Get the data color.
        Acoustics::FITKAbstractSEASubSys::SEASubSysType ssType = subSys->getSEASubSysType();
        switch (ssType)
        {
        case Acoustics::FITKAbstractSEASubSys::SEAFlatPlate:
        case Acoustics::FITKAbstractSEASubSys::SEASinglyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEADoublyCurvedShell:
        case Acoustics::FITKAbstractSEASubSys::SEACylinderShell:
        {
            Acoustics::FITKAbstractSEASubSysShell* shell = dynamic_cast<Acoustics::FITKAbstractSEASubSysShell*>(subSys);
            if (!shell)
            {
                return false;
            }

            // Get the default shell color.
            QColor defaultColor;
            Acoustics::FITKAcousticsAbsPhysicsProp* phyProp = shell->getPropSectionObj();
            if (phyProp)
            {
                float phyColor3[3]{ 0., 0., 0. };
                phyProp->getColor(phyColor3);
                defaultColor = QColor::fromRgbF(phyColor3[0], phyColor3[1], phyColor3[2]);
            }
            else
            {
                defaultColor = FITKAcousticsVTKCommons::s_SEASubSysShellColor;
            }

            // Try to get the NCT color.
            Acoustics::FITKAcousticsAbsNCT* oNCT = shell->getOutsideNCT();
            Acoustics::FITKAcousticsAbsNCT* iNCT = shell->getInsideNCT();

            QColor colorIn, colorOut;

            if (oNCT)
            {
                float color3[3]{ 0., 0., 0. };
                oNCT->getColor(color3);
                colorOut = QColor::fromRgbF(color3[0], color3[1], color3[2]);
            }
            else
            {
                colorOut = defaultColor;
            }

            if (iNCT)
            {
                float color3[3]{ 0., 0., 0. };
                iNCT->getColor(color3);
                colorIn = QColor::fromRgbF(color3[0], color3[1], color3[2]);
            }
            else
            {
                colorIn = defaultColor;
            }

            // Update the data color array.
            setDataSetColor(dataSet, colorOut, colorIn, DATA_COLOR_ARRAY_NAME);
            break;
        }
        case Acoustics::FITKAbstractSEASubSys::SEACavity:
        {
            //判断声腔材料是否存在
            Acoustics::FITKSEASubSysCavity* cavity = dynamic_cast<Acoustics::FITKSEASubSysCavity*>(subSys);
            if (cavity == nullptr)return false;
            Acoustics::FITKAcousticsMaterialsFluid* fluidMaterial = dynamic_cast<Acoustics::FITKAcousticsMaterialsFluid*>(cavity->getAcousticsMaterial());
            //判断材料是否是流体材料
            QColor color;
            if (fluidMaterial) {
                float rgb[3] = { 0,0,0 };
                fluidMaterial->getColor(rgb);
                color = QColor::fromRgbF(rgb[0], rgb[1], rgb[2]);
            }
            else {
                color = FITKAcousticsVTKCommons::s_SEASubSysCavityColor;
            }

            // Update the data color array.
            setDataSetColor(dataSet, color, DATA_COLOR_ARRAY_NAME);
            break;
        }
        default:
            return false;
        }

        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateFESubSystemDataSetColor(int dataId)
    {
        if (m_FEModel == nullptr || m_FEModel->getFESubSysManager() == nullptr) {
            return false;
        }

        Acoustics::FITKAbstractFESubSys* feSubSys = m_FEModel->getFESubSysManager()->getDataByID(dataId);
        if (feSubSys == nullptr) {
            return false;
        }

        Acoustics::FITKAcousticsFESubSysElementList* eleList = m_FEModel->getFESubSysElementList();
        if (eleList == nullptr) {
            return false;
        }

        vtkDataSet* dataSet = m_FESubSysDataSetHash.value(feSubSys);
        if (dataSet == nullptr) {
            return false;
        }

        switch (feSubSys->getFESubSysType()){
        case Acoustics::FITKAbstractFESubSys::FEStructure: {
            if (feSubSys->getEnableState() == true) {
                Acoustics::FITKFESubSysStructure* structure = dynamic_cast<Acoustics::FITKFESubSysStructure*>(feSubSys);
                if (structure == nullptr)return false;
                QList<int> eleIDList = structure->getElementsID();
                if (eleIDList.isEmpty())return false;
                vtkSmartPointer<vtkUnsignedCharArray> colorArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
                colorArray->SetNumberOfComponents(3);
                colorArray->SetNumberOfTuples(eleIDList.size() * 2);
                colorArray->SetName(DATA_COLOR_ARRAY_NAME);

                //单元颜色添加
                for (int i = 0; i < eleIDList.size(); i++) {
                    int eleID = eleIDList[i];
                    bool isFEProperty = false;
                    int elePropID = eleList->getElementPropID(eleID, &isFEProperty);
                    Acoustics::FITKAcousticsAbsPhysicsProp* acousPhyProp = FITKDATAREPO->getTDataByID<Acoustics::FITKAcousticsAbsPhysicsProp>(elePropID);
                    Interface::FITKAbstractSection* section = FITKDATAREPO->getTDataByID<Interface::FITKAbstractSection>(elePropID);
                    QColor color;
                    if (acousPhyProp) {
                        float colorDouble[3] = { 0,0,0 };
                        acousPhyProp->getColor(colorDouble);
                        color = QColor::fromRgbF(colorDouble[0], colorDouble[1], colorDouble[2]);
                    }
                    else if (section) {
                        int secColorPos = FITKAPP->getGlobalData()->getRunTimeSetting()->getValue("SECTIONCOLOR").toInt();
                        color = section->getUserData(secColorPos).value<QColor>();
                    }
                    else {
                        color = FITKAcousticsVTKCommons::getFESubSysStructureColor(true);
                    }

                    colorArray->SetComponent(i, 0, color.red());
                    colorArray->SetComponent(i, 1, color.green());
                    colorArray->SetComponent(i, 2, color.blue());
                    colorArray->SetComponent(eleIDList.count() + i, 0, color.red());
                    colorArray->SetComponent(eleIDList.count() + i, 1, color.green());
                    colorArray->SetComponent(eleIDList.count() + i, 2, color.blue());
                }
                setDataSetColor(dataSet, colorArray);
            }
            else {
                setDataSetColor(dataSet, FITKAcousticsVTKCommons::getFESubSysStructureColor(false), DATA_COLOR_ARRAY_NAME);
            }
            break;
        }
        case Acoustics::FITKAbstractFESubSys::FEAcoustic:
            Acoustics::FITKFESubSysAcoustic* cavity = dynamic_cast<Acoustics::FITKFESubSysAcoustic*>(feSubSys);
            if (cavity == nullptr)return false;
            QList<int> eleIDList = cavity->getElementsID();
            if (eleIDList.isEmpty())return false;

            //创建VTK颜色数组
            vtkSmartPointer<vtkUnsignedCharArray> colorArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
            colorArray->SetNumberOfComponents(3);
            colorArray->SetNumberOfTuples(eleIDList.count() * 2);
            colorArray->SetName(DATA_COLOR_ARRAY_NAME);

            //单元颜色添加
            for (int i = 0; i < eleIDList.size(); i++) {
                int eleID = eleIDList[i];
                bool isFEProperty = false;
                int elePropID = eleList->getElementPropID(eleID, &isFEProperty);
                Acoustics::FITKAcousticsMaterialsFluid* fluidMaterial = FITKDATAREPO->getTDataByID<Acoustics::FITKAcousticsMaterialsFluid>(elePropID);

                QColor color; 
                if (fluidMaterial != nullptr) {
                    float rgb[3] = { 0,0,0 };
                    fluidMaterial->getColor(rgb);
                    color = QColor::fromRgbF(rgb[0], rgb[1], rgb[2]);
                }
                else {
                    color = FITKAcousticsVTKCommons::getFESubSysAcousticColor();
                }

                colorArray->SetComponent(i, 0, color.red());
                colorArray->SetComponent(i, 1, color.green());
                colorArray->SetComponent(i, 2, color.blue());
                colorArray->SetComponent(eleIDList.count() + i, 0, color.red());
                colorArray->SetComponent(eleIDList.count() + i, 1, color.green());
                colorArray->SetComponent(eleIDList.count() + i, 2, color.blue());
            }
            setDataSetColor(dataSet, colorArray);
            break;
        }
        return true;
    }

    vtkMultiBlockDataSet* FITKAcousticsVTKSharedDataManager::getSEAJunctionsMultiDataSet(int seaJuncEnum)
    {
        // Type value check.
        vtkMultiBlockDataSet* mDataSet{ nullptr };
        switch (seaJuncEnum)
        {
        case Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction:
        case Acoustics::FITKAbstractJunction::JunctionType::SEALineJunction:
        case Acoustics::FITKAbstractJunction::JunctionType::SEAAreaJunction:
            break;
        default:
            return nullptr;
        }

        // Get or create the dataset by the SEA junction type.
        if (m_SEAJunctionsDataSetHash.contains(seaJuncEnum))
        {
            mDataSet = m_SEAJunctionsDataSetHash[seaJuncEnum];
        }
        else
        {
            mDataSet = vtkMultiBlockDataSet::New();
            m_SEAJunctionsDataSetHash.insert(seaJuncEnum, mDataSet);
        }

        return mDataSet;
    }

    vtkDataSet* FITKAcousticsVTKSharedDataManager::getSEAJunctionDataSet(int dataId, int & blockIndex)
    {
        blockIndex = -1;

        // ID check.
        if (!m_SEAJuncMgr)
        {
            return nullptr;
        }

        // Get the sub-system data.
        Acoustics::FITKAbstractJunction* junc = m_SEAJuncMgr->getDataByID(dataId);
        if (!junc)
        {
            return nullptr;
        }

        // Find the dataset.
        vtkDataSet* dataSet = m_SEAJuncDataSetHash.value(junc, nullptr);
        if (!dataSet)
        {
            return nullptr;
        }

        // Get the multi block dataset and find the index of the sub dataset.
        vtkMultiBlockDataSet* mDataSet = m_SEAJunctionsDataSetHash.value(junc->getJunctiontType(), nullptr);
        if (!mDataSet)
        {
            return dataSet;
        }

        int nBlocks = mDataSet->GetNumberOfBlocks();
        for (int i = 0; i < nBlocks; i++)
        {
            if (dataSet == mDataSet->GetBlock(i))
            {
                blockIndex = i;
                break;
            }
        }

        return dataSet;
    }

    bool FITKAcousticsVTKSharedDataManager::updateSEAJunctionDataSet(int dataId)
    {
        // ID check.
        if (!m_SEAJuncMgr || !m_SEASubSysMgr)
        {
            return false;
        }

        // Get the junction type.
        Acoustics::FITKAbstractJunction* junc = m_SEAJuncMgr->getDataByID(dataId);
        if (!junc)
        {
            return false;
        }

        // Generate the data and add to the multi dataset.
        Acoustics::FITKAbstractJunction::JunctionType sjType = junc->getJunctiontType();
        vtkMultiBlockDataSet* mDataSet = getSEAJunctionsMultiDataSet(sjType);
        if (!mDataSet)
        {
            return false;
        }

        vtkSmartPointer<vtkUnstructuredGrid> ugrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
        ugrid->SetPoints(points);

        vtkSmartPointer<vtkIntArray> idArray = vtkSmartPointer<vtkIntArray>::New();
        idArray->SetName(DATA_ID_ARRAY_NAME);

        switch (sjType)
        {
        case Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction:
        {
            Acoustics::FITKSEAJunctionPoint* jPoint = dynamic_cast<Acoustics::FITKSEAJunctionPoint*>(junc);
            if (!jPoint)
            {
                return false;
            }

            // Get the generated SEA node id.
            int centerNodeId = jPoint->getPointID();
            double pos3[3]{ 0., 0., 0. };
            bool flag = FITKAcousticsVTKCommons::GetSEANodePositionById(m_SEANodes, centerNodeId, pos3);
            Q_UNUSED(flag);

            // Generate the data set.
            points->InsertNextPoint(pos3);

            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            cell->InsertNextId(0);
            ugrid->InsertNextCell(VTKCellType::VTK_VERTEX, cell);

            break;
        }
        case Acoustics::FITKAbstractJunction::JunctionType::SEALineJunction:
        {
            Acoustics::FITKSEAJunctionLine* jLine = dynamic_cast<Acoustics::FITKSEAJunctionLine*>(junc);
            if (!jLine)
            {
                return false;
            }

            // Get the junction points of the line.
            QList<int> ids = jLine->getPoints();
            for (const int & id : ids)
            {
                double pos3[3]{ 0., 0., 0. };
                bool flag = FITKAcousticsVTKCommons::GetSEANodePositionById(m_SEANodes, id, pos3);
                Q_UNUSED(flag);

                points->InsertNextPoint(pos3);
            }

            // Generate the poly line cell.            
            vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
            for (int i = 0; i < points->GetNumberOfPoints(); i++)
            {
                cell->InsertNextId(i);
            }

            ugrid->InsertNextCell(VTKCellType::VTK_POLY_LINE, cell);

            break;
        }
        case Acoustics::FITKAbstractJunction::JunctionType::SEAAreaJunction:
        {
            Acoustics::FITKSEAJunctionArea* jArea = dynamic_cast<Acoustics::FITKSEAJunctionArea*>(junc);
            if (!jArea)
            {
                return false;
            }

            // Use the SEA sub-system vtk data.
            int shellId = jArea->getConnectionShellID();

            // Old version.
            //@{
            //int dataIndex = -1;
            //vtkDataSet* dataSetSS = getSEASubSystemDataSet(shellId, dataIndex);
            //Q_UNUSED(dataIndex);
            //if (!dataSetSS)
            //{
            //    return false;
            //}

            //ugrid->DeepCopy(dataSetSS);
            //@}

            // New version.
            //@{
            // Generate points.
            Acoustics::FITKAbstractSEASubSys* subSys = m_SEASubSysMgr->getDataByID(shellId);
            Acoustics::FITKAbstractSEASubSysShell* shell = dynamic_cast<Acoustics::FITKAbstractSEASubSysShell*>(subSys);
            if (!shell)
            {
                return false;
            }

            QHash<int, int> nodeIdPointIndexHash;
            generateSEASubSysNodes(shell, points, nodeIdPointIndexHash);

            // Get all triangles.
            Acoustics::FITKAcousticsTriangles* tris = shell->getTriangleMesh();
            if (!tris)
            {
                return false;
            }

            int nTris = tris->getElementCount();
            for (int i = 0; i < nTris; i++)
            {
                Interface::FITKAbstractElement* tri = tris->getElementAt(i);
                if (!tri)
                {
                    continue;
                }

                // Check the triangle.
                int nNodes = tri->getNodeCount();
                if (nNodes != 3)
                {
                    continue;
                }

                // Get the node ids.
                int nodeId_1 = tri->getNodeID(0);
                int nodeId_2 = tri->getNodeID(1);
                int nodeId_3 = tri->getNodeID(2);

                // Get the node indice.
                int ptIndex_1 = nodeIdPointIndexHash.value(nodeId_1, -1);
                int ptIndex_2 = nodeIdPointIndexHash.value(nodeId_2, -1);
                int ptIndex_3 = nodeIdPointIndexHash.value(nodeId_3, -1);

                if (ptIndex_1 == -1 || ptIndex_2 == -1 || ptIndex_3 == -1)
                {
                    qDebug() << QString("Invalid node id in SEA sub-systems!");
                    qDebug() << QString("Triangle node ids: %1, %2, %3.").arg(nodeId_1).arg(nodeId_2).arg(nodeId_3);
                    qDebug() << QString("Triangle node indice in VTK: %1, %2, %3.").arg(ptIndex_1).arg(ptIndex_2).arg(ptIndex_3);
                    continue;
                }

                // Add a triangle cell.
                vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
                cell->InsertNextId(ptIndex_1);
                cell->InsertNextId(ptIndex_2);
                cell->InsertNextId(ptIndex_3);
                ugrid->InsertNextCell(VTKCellType::VTK_TRIANGLE, cell);
            }
            //@}

            break;
        }
        default:
            return false;
        }

        // Fill the data id array.
        idArray->SetNumberOfValues(ugrid->GetNumberOfCells());
        idArray->FillComponent(0, dataId);

        // Add or replace data id array.
        vtkCellData* cellData = ugrid->GetCellData();
        if (cellData)
        {
            cellData->AddArray(idArray);
        }

        // Get the enable flag and get the color.
        double color3[3]{ 0., 0., 0. };
        if (junc->getEnabledJunction())
        {
            setDataSetColor(ugrid, FITKAcousticsVTKCommons::s_SEAJunctionEnabledColor, DATA_COLOR_ARRAY_NAME);
        }
        else
        {
            setDataSetColor(ugrid, FITKAcousticsVTKCommons::s_SEAJunctionDisabledColor, DATA_COLOR_ARRAY_NAME);
        }

        m_SEAJuncDataObjDataSetHash.insert(dataId, mDataSet);

        vtkDataSet* dataSet = m_SEAJuncDataSetHash.value(junc, nullptr);
        if (dataSet)
        {
            // Deep copy the dataset.
            vtkDataSet* dataSet = m_SEAJuncDataSetHash[junc];
            dataSet->DeepCopy(ugrid);
        }
        else
        {
            // Insert the grid to the multi dataset.
            // int dataIndex = m_SEAJuncMgr->getDataIndex(junc);
            int dataIndex = mDataSet->GetNumberOfBlocks();
            mDataSet->SetBlock(dataIndex, ugrid);

            // Save the dataset.
            m_SEAJuncDataSetHash.insert(junc, ugrid);

            // Connect delete signal.
            connect(junc, &Acoustics::FITKSEAAbstractJunction::dataObjectDestoried, this, [&](Core::FITKAbstractDataObject* objDelete)
            {
                if (!objDelete)
                {
                    return;
                }

                int dataDelId = objDelete->getDataObjectID();

                vtkDataSet* dataSet = m_SEAJuncDataSetHash.take(objDelete);
                vtkMultiBlockDataSet* mDS = m_SEAJuncDataObjDataSetHash.take(dataDelId);
                if (dataSet && mDS)
                {
                    // Remove the data from multi blcok dataset.
                    int nBlocks = mDS->GetNumberOfBlocks();
                    for (int i = 0; i < nBlocks; i++)
                    {
                        if (dataSet == mDS->GetBlock(i))
                        {
                            mDS->RemoveBlock(i);
                            break;
                        }
                    }
                }
            });
        }

        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateSEAJunctionDataSetColor(int dataId)
    {
        // ID check.
        if (!m_SEAJuncMgr)
        {
            return false;
        }

        // Get the junction enable flag.
        Acoustics::FITKAbstractJunction* junction = m_SEAJuncMgr->getDataByID(dataId);
        if (!junction)
        {
            return false;
        }

        int dataIndex = -1;
        vtkDataSet* dataSet = FITKAcousticsVTKSharedDataManager::GetInstance()->getSEAJunctionDataSet(dataId, dataIndex);
        Q_UNUSED(dataIndex);

        if (!dataSet)
        {
            return false;
        }

        bool enableFlag = junction->getEnabledJunction();

        // Set the color.
        if (enableFlag)
        {
            setDataSetColor(dataSet, FITKAcousticsVTKCommons::s_SEAJunctionEnabledColor, DATA_COLOR_ARRAY_NAME);
        }
        else
        {
            setDataSetColor(dataSet, FITKAcousticsVTKCommons::s_SEAJunctionDisabledColor, DATA_COLOR_ARRAY_NAME);
        }

        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateFEFaceDataSet(int dataId)
    {
        if (m_FEModel == nullptr || m_FEModel->getFEFaceManager() == nullptr)
            return false;
        Acoustics::FITKAcousticsFEFace* feFace = m_FEModel->getFEFaceManager()->getDataByID(dataId);
        if (feFace == nullptr)
            return false;

        Acoustics::FITKAcousticsTriangles* feFaceEleS = feFace->getTriangleMesh();
        if (feFaceEleS == nullptr)
            return false;

        vtkSmartPointer<vtkUnstructuredGrid> grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
        vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
        grid->SetPoints(points);

        //添加信息数据
        vtkSmartPointer<vtkIntArray> idArray = vtkSmartPointer<vtkIntArray>::New();
        idArray->SetName(DATA_ID_ARRAY_NAME);

        for (int i = 0; i < feFaceEleS->getElementCount(); i++) {
           Interface::FITKAbstractElement* ele = feFaceEleS->getElementAt(i);
           if (ele == nullptr)continue;

           //创建单元
           vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
           
           for (int pointID : ele->getAllNodes()) {
               double pos3[3]{ 0., 0., 0. };
               Core::FITKNode* node = m_SEANodes->getNodeByID(pointID);
               if (node) {
                   node->getCoor(pos3);
               }
               int iPt = points->InsertNextPoint(pos3);
               cell->InsertNextId(iPt);
           }

           //判断是板还是梁
           int eleVTKID = -1;
           switch (ele->getEleType()) {
           case Interface::FITKModelEnum::Tri3:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_TRIANGLE, cell); break;
           case Interface::FITKModelEnum::Tri6:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_TRIANGLE, cell); break;
           case Interface::FITKModelEnum::Quad4:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUAD, cell); break;
           case Interface::FITKModelEnum::Quad8:eleVTKID = grid->InsertNextCell(VTKCellType::VTK_QUADRATIC_QUAD, cell); break;
           }
        }

        if (m_FEFaceObjDataSet == nullptr) {
            getFEFaceMultiDataSet();
        }

        //数组添加数据id
        idArray->SetNumberOfValues(grid->GetNumberOfCells());
        idArray->FillComponent(0, dataId);
        //添加数据组
        vtkCellData* cellData = grid->GetCellData();
        if (cellData) {
            cellData->AddArray(idArray);
        }

        //记录数据
        vtkDataSet* dataSet = m_FEFaceDataSetHash.value(feFace, nullptr);
        if (dataSet){
            vtkDataSet* dataSet = m_FEFaceDataSetHash[feFace];
            dataSet->DeepCopy(grid);
        }
        else
        {
            int dataIndex = m_FEFaceObjDataSet->GetNumberOfBlocks();
            m_FEFaceObjDataSet->SetBlock(dataIndex, grid);

            m_FEFaceDataSetHash.insert(feFace, grid);

            // Connect delete signal.
            connect(feFace, &Acoustics::FITKAcousticsFEFace::dataObjectDestoried, this, [&](Core::FITKAbstractDataObject* objDelete)
            {
                if (!objDelete) {
                    return;
                }

                vtkDataSet* dataSet = m_FEFaceDataSetHash.take(objDelete);
                if (dataSet && m_FEFaceObjDataSet)
                {
                    //清除数据块中的当前数据
                    int nBlocks = m_FEFaceObjDataSet->GetNumberOfBlocks();
                    for (int i = 0; i < nBlocks; i++)
                    {
                        if (dataSet == m_FEFaceObjDataSet->GetBlock(i))
                        {
                            m_FEFaceObjDataSet->RemoveBlock(i);
                            break;
                        }
                    }
                }
            });
        }
        return true;
    }

    bool FITKAcousticsVTKSharedDataManager::updateFEFaceDataSetColor(int dataId)
    {
        // ID check.
        if (m_FEModel == nullptr)return false;

        // Get the junction enable flag.
        Acoustics::FITKAcousticsFEFace* feFace = m_FEModel->getFEFaceManager()->getDataByID(dataId);
        if (feFace == nullptr)return false;

        int dataIndex = -1;
        vtkDataSet* dataSet = getFEFacesDataSet(dataId, dataIndex);
        Q_UNUSED(dataIndex);

        if (!dataSet) {
            return false;
        }
        setDataSetColor(dataSet, FITKAcousticsVTKCommons::s_FEFaceColor, DATA_COLOR_ARRAY_NAME);
        return true;
    }

    vtkDataSet* FITKAcousticsVTKSharedDataManager::getDataSetByDataId(int dataId)
    {
        // Check the data object.
        Core::FITKAbstractDataObject* obj = FITKDATAREPO->getDataByID(dataId);
        if (!obj)
        {
            return nullptr;
        }

        vtkDataSet* dataSet{ nullptr };

        // Try to find in SEA sub-system map.
        dataSet = m_SEASubSysDataSetHash.value(obj, nullptr);
        if (dataSet)
        {
            return dataSet;
        }

        // Try to find in SEA junction map.
        dataSet = m_SEAJuncDataSetHash.value(obj, nullptr);
        if (dataSet)
        {
            return dataSet;
        }

        //查找FE面对象
        dataSet = m_FEFaceDataSetHash.value(obj, nullptr);
        if (dataSet)
        {
            return dataSet;
        }

        //查找FE子系统对象
        dataSet = m_FESubSysDataSetHash.value(obj, nullptr);
        if (dataSet)
        {
            return dataSet;
        }
        
        return nullptr;
    }

    void FITKAcousticsVTKSharedDataManager::generateSEASubSysNodes(Acoustics::FITKAbstractSEASubSys* seaSubSys, vtkPoints* points, QHash<int, int> & nodeIdPointIndexHash)
    {
        if (!m_SEANodes || !seaSubSys || !points)
        {
            return;
        }

        nodeIdPointIndexHash.clear();

        const QList<int> nodeIds = seaSubSys->getTriangleNodeIDs();

        // Get the SEA nodes points data.
        double pos3[3]{ 0., 0., 0. };
        for (const int & nodeId : nodeIds)
        {
            // Add a ( 0., 0., 0.) point while the node is invalid.
            Core::FITKNode* node = m_SEANodes->getNodeByID(nodeId);
            if (node)
            {
                node->getCoor(pos3);
            }

            int iPt = points->InsertNextPoint(pos3);

            // Save the index hash.
            nodeIdPointIndexHash.insert(nodeId, iPt);
        }
    }

    double FITKAcousticsVTKSharedDataManager::getNodeWorldSizeByRatio(double scaleFactor)
    {
        // Get the bounds.
        double bds6[6]{ 0., 0., 0., 0., 0., 0. };
        if (!getSEANodesBounds(bds6))
        {
            return 0.;
        }

        double sizeRatio = 0.5;
        AppFrame::FITKRunTimeSetting* rtSettings = FITKAPP->getGlobalData()->getRunTimeSetting();
        if (rtSettings)
        {
            QVariant var = rtSettings->getValue(RTS_KEY_SIZE_RATIO_POINTS);
            if (var.isValid())
            {
                sizeRatio = var.toBool();
            }
        }

        // Get the bounds and get the max length of x, y or z.
        double xLen = bds6[1] - bds6[0];
        double yLen = bds6[3] - bds6[2];
        double zLen = bds6[5] - bds6[4];

        double scale = sqrt(xLen * xLen + yLen * yLen + zLen * zLen);
        if (scale <= 0)
        {
            return 0.;
        }

        // Calculate the glyph size.
        return sizeRatio * scale * 0.015 * scaleFactor;
    }

    double FITKAcousticsVTKSharedDataManager::getNodeWorldSizeByRatioWithDensity(double scaleFactor)
    {
        // Get the bounds.
        double bds6[6]{ 0., 0., 0., 0., 0., 0. };
        if (!getSEANodesBounds(bds6))
        {
            return 0.;
        }

        double sizeRatio = 0.5;
        AppFrame::FITKRunTimeSetting* rtSettings = FITKAPP->getGlobalData()->getRunTimeSetting();
        if (rtSettings)
        {
            QVariant var = rtSettings->getValue(RTS_KEY_SIZE_RATIO_POINTS);
            if (var.isValid())
            {
                sizeRatio = var.toBool();
            }
        }

        // Get the bounds and get the max length of x, y or z.
        double xLen = bds6[1] - bds6[0];
        double yLen = bds6[3] - bds6[2];
        double zLen = bds6[5] - bds6[4];

        double scale = sqrt(xLen * xLen + yLen * yLen + zLen * zLen);
        if (scale <= 0)
        {
            return 0.;
        }

        // Get the volume of the bounds.
        double vol = xLen * yLen * zLen;

        // Get the density.
        vtkPoints* seaPoints = getSEANodesPoints();
        if (!seaPoints)
        {
            return false;
        }

        double den = seaPoints->GetNumberOfPoints() / vol;
        double denScale = 1. / ((den > 1.) ? (den / 5.) : 1.);

        // Calculate the glyph size.
        return sizeRatio * scale * 0.015 * scaleFactor * denScale;
    }

    double FITKAcousticsVTKSharedDataManager::getTubeWorldSizeByRatio(double scaleFactor)
    {
        // Get the bounds.
        double bds6[6]{ 0., 0., 0., 0., 0., 0. };
        if (!getSEANodesBounds(bds6))
        {
            return 0.;
        }

        double sizeRatio = 0.5;
        AppFrame::FITKRunTimeSetting* rtSettings = FITKAPP->getGlobalData()->getRunTimeSetting();
        if (rtSettings)
        {
            QVariant var = rtSettings->getValue(RTS_KEY_SIZE_RATIO_LINES);
            if (var.isValid())
            {
                sizeRatio = var.toBool();
            }
        }

        // Get the bounds and get the max length of x, y or z.
        double xLen = bds6[1] - bds6[0];
        double yLen = bds6[3] - bds6[2];
        double zLen = bds6[5] - bds6[4];

        double scale = sqrt(xLen * xLen + yLen * yLen + zLen * zLen);
        if (scale <= 0)
        {
            return 0.;
        }

        // Calculate the tube radius.
        return sizeRatio * scale * scaleFactor * 0.01;
    }

    vtkImageData* FITKAcousticsVTKSharedDataManager::getSEASemiInfFluidPicData(bool enable, bool highlight)
    {
        // Get the key of the picture data.
        int key = -1;
        if (enable && !highlight)
        {
            key = PIC_TYPE_SIF;
        }
        else if (enable && highlight)
        {
            key = PIC_TYPE_SIF_HL;
        }
        else if (!enable && !highlight)
        {
            key = PIC_TYPE_SIF_DIS;
        }
        else if (!enable && highlight)
        {
            key = PIC_TYPE_SIF_HL_DIS;
        }

        vtkImageData* img = m_picDataDict.value(key, nullptr);
        if (img)
        {
            return img;
        }

        // Read the picture.
        QDir dir;

        // Copy the qrc picturn file to $$APP_DIR/temp/3d/.
        QString fileName = QString("semi_infinite_fluid%1.png");
        fileName = fileName.arg(getSuffixByDataFlag(enable, highlight));
        QString resFilePath = ":/resource/" + fileName;
        QString destFilePath = FITKAcousticsVTKCommons::GetTempFolder() + fileName;
       
        img = vtkImageData::New();
        bool flag = removeCacheFileAndReadPicture(resFilePath, destFilePath, img);
        if (!flag)
        {
            img->Delete();
            return nullptr;
        }

        // Save the data to the dict.
        m_picDataDict.insert(key, img);

        return img;
    }

    vtkImageData* FITKAcousticsVTKSharedDataManager::getLoadPowerPicData(bool enable, bool highlight)
    {
        // Get the key of the picture data.
        int key = -1;
        if (enable && !highlight)
        {
            key = PIC_TYPE_POWER;
        }
        else if (enable && highlight)
        {
            key = PIC_TYPE_POWER_HL;
        }
        else if (!enable && !highlight)
        {
            key = PIC_TYPE_POWER_DIS;
        }
        else if (!enable && highlight)
        {
            key = PIC_TYPE_POWER_HL_DIS;
        }

        vtkImageData* img = m_picDataDict.value(key, nullptr);
        if (img)
        {
            return img;
        }

        // Read the picture.
        QDir dir;

        // Copy the qrc picturn file to $$APP_DIR/temp/3d/.
        QString fileName = QString("power%1.png");
        fileName = fileName.arg(getSuffixByDataFlag(enable, highlight));
        QString resFilePath = ":/resource/" + fileName;
        QString destFilePath = FITKAcousticsVTKCommons::GetTempFolder() + fileName;

        img = vtkImageData::New();
        bool flag = removeCacheFileAndReadPicture(resFilePath, destFilePath, img);
        if (!flag)
        {
            img->Delete();
            return nullptr;
        }

        // Save the data to the dict.
        m_picDataDict.insert(key, img);

        return img;
    }

    vtkImageData* FITKAcousticsVTKSharedDataManager::getLoadConstraintPicData(bool enable, bool highlight)
    {
        // Get the key of the picture data.
        int key = -1;
        if (enable && !highlight)
        {
            key = PIC_TYPE_CONSTRAINT;
        }
        else if (enable && highlight)
        {
            key = PIC_TYPE_CONSTRAINT_HL;
        }
        else if (!enable && !highlight)
        {
            key = PIC_TYPE_CONSTRAINT_DIS;
        }
        else if (!enable && highlight)
        {
            key = PIC_TYPE_CONSTRAINT_HL_DIS;
        }

        vtkImageData* img = m_picDataDict.value(key, nullptr);
        if (img)
        {
            return img;
        }

        // Read the picture.
        QDir dir;

        // Copy the qrc picturn file to $$APP_DIR/temp/3d/.
        QString fileName = QString("constraint%1.png");
        fileName = fileName.arg(getSuffixByDataFlag(enable, highlight));
        QString resFilePath = ":/resource/" + fileName;
        QString destFilePath = FITKAcousticsVTKCommons::GetTempFolder() + fileName;

        img = vtkImageData::New();
        bool flag = removeCacheFileAndReadPicture(resFilePath, destFilePath, img);
        if (!flag)
        {
            img->Delete();
            return nullptr;
        }

        // Save the data to the dict.
        m_picDataDict.insert(key, img);

        return img;
    }

    vtkImageData * FITKAcousticsVTKSharedDataManager::getLoadImportPicData(bool enable, bool highlight)
    {
        // Get the key of the picture data.
        int key = -1;
        if (enable && !highlight)
        {
            key = PIC_TYPE_IMPORT;
        }
        else if (enable && highlight)
        {
            key = PIC_TYPE_IMPORT_HL;
        }
        else if (!enable && !highlight)
        {
            key = PIC_TYPE_IMPORT_DIS;
        }
        else if (!enable && highlight)
        {
            key = PIC_TYPE_IMPORT_HL_DIS;
        }

        vtkImageData* img = m_picDataDict.value(key, nullptr);
        if (img)
        {
            return img;
        }

        // Read the picture.
        QDir dir;

        // Copy the qrc picturn file to $$APP_DIR/temp/3d/.
        QString fileName = QString("import%1.png");
        fileName = fileName.arg(getSuffixByDataFlag(enable, highlight));
        QString resFilePath = ":/resource/" + fileName;
        QString destFilePath = FITKAcousticsVTKCommons::GetTempFolder() + fileName;

        img = vtkImageData::New();
        bool flag = removeCacheFileAndReadPicture(resFilePath, destFilePath, img);
        if (!flag)
        {
            img->Delete();
            return nullptr;
        }

        // Save the data to the dict.
        m_picDataDict.insert(key, img);

        return img;
    }

    vtkImageData * FITKAcousticsVTKSharedDataManager::getLoadMonopolePicData(bool enable, bool highlight)
    {
        // Get the key of the picture data.
        int key = -1;
        if (enable && !highlight)
        {
            key = PIC_TYPE_MONOPOLE;
        }
        else if (enable && highlight)
        {
            key = PIC_TYPE_MONOPOLE_HL;
        }
        else if (!enable && !highlight)
        {
            key = PIC_TYPE_MONOPOLE_DIS;
        }
        else if (!enable && highlight)
        {
            key = PIC_TYPE_MONOPOLE_HL_DIS;
        }

        vtkImageData* img = m_picDataDict.value(key, nullptr);
        if (img)
        {
            return img;
        }

        // Read the picture.
        QDir dir;

        // Copy the qrc picturn file to $$APP_DIR/temp/3d/.
        QString fileName = QString("monopole%1.png");
        fileName = fileName.arg(getSuffixByDataFlag(enable, highlight));
        QString resFilePath = ":/resource/" + fileName;
        QString destFilePath = FITKAcousticsVTKCommons::GetTempFolder() + fileName;

        img = vtkImageData::New();
        bool flag = removeCacheFileAndReadPicture(resFilePath, destFilePath, img);
        if (!flag)
        {
            img->Delete();
            return nullptr;
        }

        // Save the data to the dict.
        m_picDataDict.insert(key, img);

        return img;
    }

    void FITKAcousticsVTKSharedDataManager::deleteVtkObjs(QHash<int, vtkMultiBlockDataSet*> & objs)
    {
        for (vtkMultiBlockDataSet* mDataSet : objs.values())
        {
            if (mDataSet)
            {
                mDataSet->Delete();
            }
        }

        objs.clear();
    }

    void FITKAcousticsVTKSharedDataManager::setDataSetColor(vtkDataSet* dataSet, QColor color, QString arrayName)
    {
        if (!dataSet || !color.isValid())
        {
            return;
        }

        vtkCellData* cellData = dataSet->GetCellData();
        if (!cellData)
        {
            return;
        }

        // Get or create the color array.
        vtkUnsignedCharArray* colorArray = vtkUnsignedCharArray::SafeDownCast(cellData->GetArray(arrayName.toUtf8().data()));
        if (colorArray)
        {
            colorArray->Reset();
            colorArray->SetNumberOfComponents(3);
            colorArray->SetNumberOfValues(0);
        }
        else
        {
            vtkSmartPointer<vtkUnsignedCharArray> newColorArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
            newColorArray->SetName(arrayName.toUtf8().data());
            newColorArray->SetNumberOfComponents(3);
            cellData->AddArray(newColorArray);
            colorArray = newColorArray;
        }

        int nCells = dataSet->GetNumberOfCells();
        colorArray->SetNumberOfTuples(nCells);

        colorArray->FillComponent(0, color.red());
        colorArray->FillComponent(1, color.green());
        colorArray->FillComponent(2, color.blue());
    }

    void FITKAcousticsVTKSharedDataManager::setDataSetColor(vtkDataSet* dataSet, QColor colorFront, QColor colorBack, QString arrayName)
    {
        if (!dataSet || !colorFront.isValid() || !colorBack.isValid())
        {
            return;
        }

        vtkCellData* cellData = dataSet->GetCellData();
        if (!cellData)
        {
            return;
        }

        int nCells = dataSet->GetNumberOfCells();
        bool cellsCheck = (nCells % 2 == 0);
        if (!cellsCheck)
        {
            return;
        }

        // Get or create the color array.
        vtkUnsignedCharArray* colorArray = vtkUnsignedCharArray::SafeDownCast(cellData->GetArray(arrayName.toUtf8().data()));
        if (colorArray)
        {
            colorArray->Reset();
            colorArray->SetNumberOfComponents(3);
            colorArray->SetNumberOfValues(0);
        }
        else
        {
            vtkSmartPointer<vtkUnsignedCharArray> newColorArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
            newColorArray->SetName(arrayName.toUtf8().data());
            newColorArray->SetNumberOfComponents(3);
            cellData->AddArray(newColorArray);
            colorArray = newColorArray;
        }

        colorArray->SetNumberOfTuples(nCells);

        int mid = nCells / 2;

        int fR = colorFront.red();
        int fG = colorFront.green();
        int fB = colorFront.blue();

        int bR = colorBack.red();
        int bG = colorBack.green();
        int bB = colorBack.blue();

        // Add front face color.
        for (int i = 0; i < mid; i++)
        {
            colorArray->SetComponent(i, 0, fR);
            colorArray->SetComponent(i, 1, fG);
            colorArray->SetComponent(i, 2, fB);
        }

        // Add back face color.
        for (int i = mid; i < nCells; i++)
        {
            colorArray->SetComponent(i, 0, bR);
            colorArray->SetComponent(i, 1, bG);
            colorArray->SetComponent(i, 2, bB);
        }
    }

    void FITKAcousticsVTKSharedDataManager::setDataSetColor(vtkDataSet * dataSet, vtkUnsignedCharArray * colorArray)
    {
        if (dataSet == nullptr || colorArray == nullptr)return;
        vtkCellData* cellData = dataSet->GetCellData();
        if (cellData == nullptr)return;

        // Get or create the color array.
        vtkUnsignedCharArray* dataColorArray = vtkUnsignedCharArray::SafeDownCast(cellData->GetArray(colorArray->GetName()));
        if (dataColorArray){
            dataColorArray->Reset();
        }
        else
        {
            vtkSmartPointer<vtkUnsignedCharArray> newColorArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
            newColorArray->SetName(colorArray->GetClassName());
            cellData->AddArray(newColorArray);
            dataColorArray = newColorArray;
        }

        dataColorArray->SetNumberOfComponents(3);
        dataColorArray->SetNumberOfTuples(dataSet->GetNumberOfCells());
        dataColorArray->DeepCopy(colorArray);
    }

    bool FITKAcousticsVTKSharedDataManager::removeCacheFileAndReadPicture(QString resFilePath, QString destFilePath, vtkImageData* imageData)
    {
        if (!imageData)
        {
            return false;
        }

        QFile::remove(destFilePath);
        QDir dir;

        // Make folder and copy file.
        dir.mkpath(FITKAcousticsVTKCommons::GetTempFolder());
        QFile::copy(resFilePath, destFilePath);

        if (!QFile::exists(destFilePath))
        {
            return false;
        }

        // Read and save the picture.
        vtkSmartPointer<vtkPNGReader> reader = vtkSmartPointer<vtkPNGReader>::New();
        reader->SetFileName(destFilePath.toUtf8());
        reader->Update();

        imageData->DeepCopy(reader->GetOutput());

        return true;
    }

    QString FITKAcousticsVTKSharedDataManager::getSuffixByDataFlag(bool enable, bool highlight)
    {
        QString suffix;
        if (enable && !highlight)
        {
            return suffix;
        }

        if (highlight)
        {
            suffix += "_hl";
        }

        if (!enable)
        {
            suffix += "_disable";
        }

        return suffix;
    }
}